// 装饰器其实就是一个方法
// 定义:装饰器是一种特殊的声明，它能够被附加到类声明，方法，属性或参数上，可以修改类行为
// 类装饰器
// 普通装饰器(无法传参)
/* function logClass(params:any) {
    console.log(params);
    // params就是当前类
    params.prototype.apiUrl = 'xxx'; //动态扩展的属性
    params.prototype.run = function(){
        console.log('我是run方法');
    };
}

@logClass
class HttpClient{
    constructor(){

    }
    getData(){

    }
}
var http:any = new HttpClient()
console.log(http.apiUrl);
http.run(); */
// 装饰器:装饰器工厂(带参数)
/* function logClass(params:string) {

    return function (target:any) {
        console.log(target,params);
        target.prototype.apiUrl = params
    }
}

@logClass('http://www.baidu.com')
class HttpClient{
    constructor(){
    }
    getData(){
    }
}
let http:any = new HttpClient()
console.log(http.apiUrl); */
// 类装饰器重载构造函数 ====
/* function logClass(target:any) {
    console.log(target);
    return class extends target {
        apiUrl:any =  '我是修改后的数据'
        getData(){
            this.apiUrl = this.apiUrl + '-----'
            console.log(this.apiUrl );
        }
    }
}

@logClass
class HttpClient {
    public apiUrl:string | undefined;
    constructor(parameters) {
        this.apiUrl = '我是构造函数里面的apiUrl'
    }
    getData(){
        console.log(this.apiUrl);
    }
}

let http = new HttpClient();
http.getData() */
// 属性装饰器
// 类装饰器
// 属性装饰器会在运行时当作函数调用，传入下列2个参数
//      1.对于静态成员来说是类的构造函数，对于实例成员是类的原型对象
//      2.成员
/* function logClass(params:string) {
    return function (target:any) {
        // console.log(target,params);
        // target.prototype.apiUrl = params
    }
}

function logProperty(params:any) {
    return function (target:any,attr:any) { //类的原型对象
        console.log(target,attr);
        target[attr] = params
    }
}

@logClass('xxx')
class HttpClient{
    @logProperty('http://www.ai')
    public url:any| undefined;
    constructor(){
    }
    getData(){
        console.log(this.url);
    }
}
let http:any = new HttpClient()
http.getData() */
// 3.方法装饰器
/* 接收三个参数：1.对于静态成员来说是类的构造函数，对于实例成员是类的原型对象
2.成员的名字 3.成员的属性描述符
*/
// 方法一
/* function get(params:any) {
    return function (target:any,methodName:any,desc:any) {
        console.log(target);
        console.log(methodName);
        console.log(desc);
        target.apiurl = 'xxxx';
        target.run = function () {
            console.log('run');
        }
    }
}

class HttpClient{
    public url:any| undefined;
    constructor(){
    }
    @get('http://www')
    getData(){
        console.log(this.url);
    }
}

let http:any = new HttpClient()
http.apiUrl
http.run()
http.getData() */
// 方法2：
/*
    return function (target:any,methodName:any,desc:any) {
        console.log(target);
        console.log(methodName);
        console.log(desc.value);
        // 修改装饰器的方法，把装饰器方法里面传入的所有的参数改为string类型

        // 1.保存当前的方法
        var oMethos = desc.value;
        // 2.重新定义方法
        desc.value = function (...args:any[]) {
            // 3.把传入的数组元素转化为字符串
            args = args.map((value) => {
                return String(value)
            })
            console.log(args);
            // 4.执行原来的方法体
            oMethos.apply(this, args);
        }
    }
}

class HttpClient{
    public url:any| undefined;
    constructor(){
    }
    @get('http://www')
    getData(...args:any[]){
        console.log('我是getData里面的方法');
    }
}
let http = new HttpClient()
http.getData(123,'xxx')

// let http:any = new HttpClient()
// http.apiUrl
// http.run()
// http.getData() */
// 4.方法参数装饰器
// 参数装饰器表达式会在运行时被调用，可以为类的原型增加一些元素数据，传入3个参数：
// 对于静态成员来说是类的构造函数，对于实例成员来说是类的原型对象；
// 方法名称，如果装饰的是构造函数的参数，则值为undefined
// 参数在函数参数列表中的索引；
/* function logParams(params:any) {
    return function(target:any,methodName:any,paramsIndex:any){
        console.log('params:', params);
        console.log(target); // 原型对象
        console.log(methodName); // 方法名称
        console.log(paramsIndex); //索引

        target.apiUrl = params
    }
}
class HttpClient {
    public url: any | undefined;
    constructor() {
    }
    getData(@logParams('sss') uuid:any){
        console.log(uuid);
    }
}

let http:any = new HttpClient()
http.getData(1234)
console.log(http.apiUrl); */
// 装饰器特殊类型声明
// 类装饰器 属性装饰器 方法装饰器 方法参数装饰器
// 装饰器执行顺序
/* function logClass1(params:string) {
    return function(target:any){
        console.log('类装饰器1');
    }
}

function logClass2(params:string) {
    return function(target:any){
        console.log('类装饰器2');
    }
}

function logAttribute(params?:string) {
    return function(target:any, attrName:any){
        console.log('属性装饰器');
    }
}
function logMethod(params?:string) {
    return function(target:any, attrName:any,desc:any){
        console.log('方法装饰器');
    }
}


function logParams1(params?:string) {
    return function(target:any, attrName:any,desc:any){
        console.log('方法参数装饰器1');
    }
}

function logParams2(params?:string) {
    return function(target:any, attrName:any,desc:any){
        console.log('方法参数装饰器2');
    }
}


@logClass1('http://www.')
@logClass2('xxx')
class HttpClient{
    @logAttribute()
    public api:string | undefined;
    constructor(){

    }
    @logMethod()
    getData() {
        return true
    }
    setData(@logParams1() attr1:any, @logParams2() attr2:any) {

    }
}
var http:any = new HttpClient()
// console.log(http.apiUrl); */
// 属性 》 方法 》 方法参数 》 类
// 如果有多个同样的装饰器，会先执行后面的
